package com.wujilee.dbredissyn.service.impl;

import com.alibaba.fastjson2.JSON;
import com.wujilee.dbredissyn.common.ServiceResult;
import com.wujilee.dbredissyn.common.redis.RedisFunction;
import com.wujilee.dbredissyn.service.RedisSynService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.swing.text.html.Option;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * @author liwuji
 * @date 2024/5/14
 * @desc
 **/
@Service
public class RedisSynServiceImpl implements RedisSynService {
    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public <T> T getValue(String prefix, String id, Class<T> tClass) {
        String obj = (String) redisTemplate.opsForValue().get(prefix + id);
        if (obj != null) {
            return JSON.parseObject(obj, tClass);
        }
        return null;
    }

    /**
     * 为了预防缓存击穿和缓存穿透提供该实现
     * @param prefix
     * @param id
     * @param tClass
     * @param function
     * @return
     * @param <T>
     */
    @Override
    public <T> T getValue(String prefix, String id, Class<T> tClass, RedisFunction<T> function) {
        String obj = (String) redisTemplate.opsForValue().get(prefix + id);
        if (obj != null) {
            return JSON.parseObject(obj, tClass);
        }
        return function.apply(null);
      
    }

    /**
     * 重点就是这里了，删除有可能失败，失败导致数据不一致的情况非常严重
     * 解决方案：双删, 设置超时
     * @param prefix
     * @param id
     */
    @Override
    public void deleteValue(String prefix, String id) {
        // 方案1 直接删除，
        redisTemplate.delete(prefix + id);
        // 方案2 ： mq异步删除  保证正常消费 如果确实有问题 ：删除失败， 要做一个报警机制/页面
        
    }


    /**
     * 时间会导致缓存穿透 击穿 和雪崩
     * 
     * 雪崩（大面积的key失效，解决方案：随机时间）
     * 缓存击穿是一个热点的Key，失效，key永不过期，读取加锁
     * @param prefix
     * @param id
     * @param t
     * @param time
     * @param <T>
     */
    @Override
    public <T> void putValue(String prefix, String id, T t, long time) {
        redisTemplate.opsForValue().set(prefix + id, JSON.toJSONString(t), time, TimeUnit.SECONDS);
    }
}
